home *** CD-ROM | disk | FTP | other *** search
/ TPUG - Toronto PET Users Group / TPUG Users Group CD / TPUG Users Group CD.iso / AMIGA / AMICUS / AMICUS09.ADF / MicroEMACS / word.c < prev    next >
C/C++ Source or Header  |  1986-05-22  |  14KB  |  501 lines

  1. /*
  2.  * The routines in this file implement commands that work word at a time.
  3.  * There are all sorts of word mode commands. If I do any sentence and/or
  4.  * paragraph mode commands, they are likely to be put in this file.
  5.  */
  6.  
  7. #include        <stdio.h>
  8. #include        "ed.h"
  9.  
  10. #define WPNULL -1 /* null word pointer */
  11.  
  12. /* Paragraph fill.  Retain indenting of first line of paragraph.  Remove
  13.  * leading spaces from other lines.  Remove extra space between words.
  14.  * Fill each line to fillcol, breaking at word boundaries.
  15.  * Delete trailing space from all lines.  
  16.  */
  17. parafill( f, n)
  18. {
  19.     register int c;            /* current char */
  20.     register short spo;            /* space offset */
  21.     register short count;
  22.     short wo;                /* word offset */
  23.     short LeftCount;
  24.     WINDOW *wp;
  25.     LINE *flp,                /* first line of paragraph */
  26.      *clp;                /* current line of paragraph */
  27.  
  28.     /* save old context */
  29.     /* we do this by creating a fake window which retains the context.
  30.      * this will be updated by the editing commands.
  31.      */
  32.         if ((wp = (WINDOW *) malloc(sizeof(WINDOW))) == NULL) {
  33.                 mlwrite("Cannot allocate WINDOW block");
  34.                 return (FALSE);
  35.         }
  36.         wp->w_bufp  = curbp;
  37.         wp->w_dotp  = curwp->w_dotp;
  38.         wp->w_doto  = curwp->w_doto;
  39.         wp->w_markp = curwp->w_markp;
  40.         wp->w_marko = curwp->w_marko;
  41.         wp->w_flag  = 0;
  42.         wp->w_force = 0;
  43.     wp->w_wndp = wheadp;
  44.     wheadp = wp;
  45.  
  46.     /* get first line of paragraph */
  47.  
  48.     for( flp = curwp->w_dotp; flp != curbp->b_linep; flp = lback( flp)) {
  49.         if( llength( flp) == 0) /* blank line, found it */
  50.         break;
  51.     }
  52.     flp = lforw( flp);
  53.     if( llength( flp) == 0) /* nothing to do */
  54.         return( TRUE);
  55.  
  56.     /* initialize */
  57.     count = 0;
  58.     curwp->w_dotp = clp = flp;
  59.  
  60.     for(;;) { /* go through all lines */
  61.     spo = count; /* set space offset at current spot */
  62.  
  63.     /* get to end of spaces */
  64.     for( ;; count++) {
  65.         c = wgetc( &clp, count);
  66.         if( (c != ' ') || (c == EOF)) break;
  67.     }
  68.     wo = count;
  69.  
  70.     /* get to end of word */
  71.     for( ;; count++) {
  72.         c = wgetc( &clp, count);
  73.         if( (c == ' ') || (c == EOF)) break;
  74.     }
  75.  
  76.     if(((clp != flp) || spo) && (spo != wo)) {
  77.     /* adjust spaces.  if at beginning of line, delete all spaces */
  78.         curwp->w_doto = spo;
  79.         if( spo) { /* past begin of line */
  80.         count += adjsp( &clp, spo, &wo);
  81.         } else { /* at begin of line */
  82.         ldelete( wo - spo, FALSE);
  83.         wo = count = 0;
  84.         }        
  85.     }
  86.  
  87.     if( count > fillcol) { /* if past fill column, break. */
  88.         if(((clp != flp) || spo) && (spo != wo)) {
  89.         /* collapse the spaces */
  90.         curwp->w_doto = spo;
  91.         ldelete( wo - spo, FALSE);
  92.         wo = spo;
  93.         }
  94.         if( wo > 0) { /* break at beginning of word */
  95.         curwp->w_doto = wo;
  96.         } else { /* break at end of word */
  97.         curwp->w_doto = count;
  98.         }
  99.         newline( FALSE, 1);
  100. /* New stuff */        
  101.         count = LeftMargin;
  102.         for ( LeftCount = 0; LeftCount < LeftMargin; LeftCount++ )
  103.             linsert( 1, ' ' );
  104. /* end of new stuff */        
  105.         clp = curwp->w_dotp; /* updated by newline */
  106.     }
  107.     if( c == EOF) break;
  108.     }
  109.     /* restore context  and delete fake window */
  110.     curwp->w_dotp = wp->w_dotp;
  111.     curwp->w_doto = wp->w_doto;
  112.     curwp->w_markp = wp->w_markp;
  113.     curwp->w_marko = wp->w_marko;
  114.     wheadp = wp->w_wndp;
  115.     free( (char *) wp);
  116.  
  117.     return( TRUE);
  118. }
  119.  
  120. /* adjust the spacing between words.  check for colons and punctuation.
  121.  * assumes spo > 0 and doto is set to spo.
  122.  */
  123. adjsp( lp, spo, wo)
  124. register LINE **lp;
  125. register short spo, *wo;
  126. {
  127. short result, spaces, n, c;
  128.  
  129. /* decide on number of spaces */
  130. switch ( lgetc( *lp, spo -1) ) 
  131.     {
  132.     case ':':
  133.     spaces = 2;
  134.     break;
  135.     case '.': case '?': case '!':    /* end of sentence punct */
  136.     spaces = 1;            /* just a guess */
  137.     n = spo - 2;
  138.     if( n == 0) /* period at beginning of line */
  139.         break;
  140.     else 
  141.         {
  142.         c = lgetc( *lp, n);
  143.         if( (('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z')) ) 
  144.             {                       /* letter */
  145.         n -= 1;
  146.         if( n == 0)
  147.             break;              /* single letter followed by . */
  148.         else 
  149.             {
  150.             c = lgetc( *lp, n);
  151.             if ( (c==' ') || (c=='.') || (c=='?') || (c=='!') )
  152.                         break;          /* single letter followed by . */
  153.                     }
  154.                 } 
  155.             else                        /* not a letter */
  156.                 break;
  157.             }
  158.         
  159.     if( *wo < llength( *lp)) 
  160.         {
  161.         c = lgetc( *lp, *wo);
  162.         if ( (c < 'A') || ('Z' < c) ) /* not a cap letter */
  163.         break;
  164.         }
  165.     spaces = 2;
  166.     break;
  167.     default:
  168.     spaces = 1;
  169.     break;
  170.     }
  171.  
  172. /* adjust them */
  173. if( (*wo - spo) == spaces)          /* perfect */
  174.     return( 0);
  175. else if ( (*wo - spo) > spaces)     /* delete extras */
  176.     {
  177.     result = *wo - spo - spaces;
  178.     ldelete( result, FALSE);
  179.     result = - result;
  180.     }
  181. else                                /* pad with spaces */
  182.     {
  183.     result = spaces - (*wo - spo);
  184.     linsert( result, ' ');
  185.     }
  186.  
  187. *lp = curwp->w_dotp;
  188. *wo = spo + spaces;
  189. return( result);
  190. }
  191.  
  192. /* Get next char, word-oriented style.  If at end of line, append next
  193.  * line by replacing newline with a space.  Return EOF
  194.  * when there is nothing left.
  195.  */
  196. wgetc( clp, n)
  197. LINE **clp;
  198. int n;
  199. {
  200.     LINE *newlp;
  201.  
  202.     if( n > llength( *clp)) {
  203.     mlwrite( "Bad para fill");
  204.     return( EOF);
  205.     }
  206.     if( n == llength( *clp)) {
  207.     newlp = lforw( *clp);
  208.     if( llength( newlp) == 0) return( EOF);
  209.     curwp->w_doto = n;
  210.     ldelete( 1, FALSE);
  211.     linsert( 1, ' ');
  212.     *clp = curwp->w_dotp;
  213.     }
  214.     return( lgetc( *clp, n));
  215. }
  216.  
  217. /* Break line on spaces. Back-over whatever precedes the point on the current
  218.  * line and stop on the first space or the beginning of the line. If we
  219.  * reach the beginning of the line, do nothing.
  220.  * Otherwise, break the line at the space, eat previous spaces, and jump
  221.  * back to the end of the word.
  222.  * Returns TRUE on success, FALSE on errors.
  223.  */
  224. wrapword()
  225. {
  226. register long    wo, spo, oldo;
  227. register LINE    *oldp;
  228.  
  229. oldp = curwp->w_dotp;
  230. oldo = curwp->w_doto;
  231.  
  232. /* back up from cursor to start of word */
  233. for( spo = oldo; spo > 0; --spo) 
  234.     if ( lgetc( oldp, spo) == ' ') 
  235.         break;
  236.     
  237. if ( spo ) 
  238.     wo = spo + 1;       /* wo points at start of word */
  239. else
  240.     return( FALSE);    /* can't do it */
  241.     
  242. for( ; spo > 0; --spo) 
  243.     if( lgetc( oldp, spo) != ' ') 
  244.         break;
  245.     
  246. if ( spo ) 
  247.     spo = spo + 1;      /* spo points at start of spaces */
  248. else
  249.     return( FALSE);    /* can't do it */
  250.  
  251. /* delete spaces and insert new line */
  252. curwp->w_doto = spo;
  253. forwdel( FALSE, wo - spo);
  254. newline( FALSE, 1);
  255.  
  256. if( oldo > spo)                /* adjust point */
  257.     curwp->w_doto = oldo - wo;
  258.  
  259. /* New stuff for LeftMargin */
  260. oldo = curwp->w_doto;            /* save old cursor position */
  261. gotobol( FALSE, 1);            /* Move to beginning of line */
  262. for ( wo = 0; wo < LeftMargin; wo++ )
  263.     linsert( 1, ' ' );            /* insert LeftMargin # of spaces */
  264. curwp->w_doto = oldo + LeftMargin;    /* restore cursor position */
  265.  
  266. return( TRUE);
  267. }
  268.                                 
  269. /*
  270.  * Move the cursor backward by "n" words. All of the details of motion are
  271.  * performed by the "backchar" and "forwchar" routines. Error if you try to
  272.  * move beyond the buffers.
  273.  */
  274. backword(f, n)
  275. {
  276.         if (n < 0)
  277.                 return (forwword(f, -n));
  278.         if (backchar(FALSE, 1) == FALSE)
  279.                 return (FALSE);
  280.         while (n--) {
  281.                 while (inword() == FALSE) {
  282.                         if (backchar(FALSE, 1) == FALSE)
  283.                                 return (FALSE);
  284.                 }
  285.                 while (inword() != FALSE) {
  286.                         if (backchar(FALSE, 1) == FALSE)
  287.                                 return (FALSE);
  288.                 }
  289.         }
  290.         return (forwchar(FALSE, 1));
  291. }
  292.  
  293. /*
  294.  * Move the cursor forward by the specified number of words. All of the motion
  295.  * is done by "forwchar". Error if you try and move beyond the buffer's end.
  296.  */
  297. forwword(f, n)
  298. {
  299.         if (n < 0)
  300.                 return (backword(f, -n));
  301.         while (n--) {
  302.                 while (inword() == FALSE) {
  303.                         if (forwchar(FALSE, 1) == FALSE)
  304.                                 return (FALSE);
  305.                 }
  306.                 while (inword() != FALSE) {
  307.                         if (forwchar(FALSE, 1) == FALSE)
  308.                                 return (FALSE);
  309.                 }
  310.         }
  311.         return (TRUE);
  312. }
  313.  
  314. /*
  315.  * Move the cursor forward by the specified number of words. As you move,
  316.  * convert any characters to upper case. Error if you try and move beyond the
  317.  * end of the buffer. Bound to "M-U".
  318.  */
  319. upperword(f, n)
  320. {
  321.         register int    c;
  322.  
  323.         if (n < 0)
  324.                 return (FALSE);
  325.         while (n--) {
  326.                 while (inword() == FALSE) {
  327.                         if (forwchar(FALSE, 1) == FALSE)
  328.                                 return (FALSE);
  329.                 }
  330.                 while (inword() != FALSE) {
  331.                         c = lgetc(curwp->w_dotp, curwp->w_doto);
  332.                         if (c>='a' && c<='z') {
  333.                                 c -= 'a'-'A';
  334.                                 lputc(curwp->w_dotp, curwp->w_doto, c);
  335.                                 lchange(WFHARD);
  336.                         }
  337.                         if (forwchar(FALSE, 1) == FALSE)
  338.                                 return (FALSE);
  339.                 }
  340.         }
  341.         return (TRUE);
  342. }
  343.  
  344. /*
  345.  * Move the cursor forward by the specified number of words. As you move
  346.  * convert characters to lower case. Error if you try and move over the end of
  347.  * the buffer. Bound to "M-L".
  348.  */
  349. lowerword(f, n)
  350. {
  351.         register int    c;
  352.  
  353.         if (n < 0)
  354.                 return (FALSE);
  355.         while (n--) {
  356.                 while (inword() == FALSE) {
  357.                         if (forwchar(FALSE, 1) == FALSE)
  358.                                 return (FALSE);
  359.                 }
  360.                 while (inword() != FALSE) {
  361.                         c = lgetc(curwp->w_dotp, curwp->w_doto);
  362.                         if (c>='A' && c<='Z') {
  363.                                 c += 'a'-'A';
  364.                                 lputc(curwp->w_dotp, curwp->w_doto, c);
  365.                                 lchange(WFHARD);
  366.                         }
  367.                         if (forwchar(FALSE, 1) == FALSE)
  368.                                 return (FALSE);
  369.                 }
  370.         }
  371.         return (TRUE);
  372. }
  373.  
  374. /*
  375.  * Move the cursor forward by the specified number of words. As you move
  376.  * convert the first character of the word to upper case, and subsequent
  377.  * characters to lower case. Error if you try and move past the end of the
  378.  * buffer. Bound to "M-C".
  379.  */
  380. capword(f, n)
  381. {
  382.         register int    c;
  383.  
  384.         if (n < 0)
  385.                 return (FALSE);
  386.         while (n--) {
  387.                 while (inword() == FALSE) {
  388.                         if (forwchar(FALSE, 1) == FALSE)
  389.                                 return (FALSE);
  390.                 }
  391.                 if (inword() != FALSE) {
  392.                         c = lgetc(curwp->w_dotp, curwp->w_doto);
  393.                         if (c>='a' && c<='z') {
  394.                                 c -= 'a'-'A';
  395.                                 lputc(curwp->w_dotp, curwp->w_doto, c);
  396.                                 lchange(WFHARD);
  397.                         }
  398.                         if (forwchar(FALSE, 1) == FALSE)
  399.                                 return (FALSE);
  400.                         while (inword() != FALSE) {
  401.                                 c = lgetc(curwp->w_dotp, curwp->w_doto);
  402.                                 if (c>='A' && c<='Z') {
  403.                                         c += 'a'-'A';
  404.                                         lputc(curwp->w_dotp, curwp->w_doto, c);
  405.                                         lchange(WFHARD);
  406.                                 }
  407.                                 if (forwchar(FALSE, 1) == FALSE)
  408.                                         return (FALSE);
  409.                         }
  410.                 }
  411.         }
  412.         return (TRUE);
  413. }
  414.  
  415. /*
  416.  * Kill forward by "n" words. Remember the location of dot. Move forward by
  417.  * the right number of words. Put dot back where it was and issue the kill
  418.  * command for the right number of characters. Bound to "M-D".
  419.  */
  420. delfword(f, n)
  421. {
  422.         register int    size;
  423.         register LINE   *dotp;
  424.         register int    doto;
  425.  
  426.         if (n < 0)
  427.                 return (FALSE);
  428.         dotp = curwp->w_dotp;
  429.         doto = curwp->w_doto;
  430.         size = 0;
  431.         while (n--) {
  432.                 while (inword() == FALSE) {
  433.                         if (forwchar(FALSE, 1) == FALSE)
  434.                                 return (FALSE);
  435.                         ++size;
  436.                 }
  437.                 while (inword() != FALSE) {
  438.                         if (forwchar(FALSE, 1) == FALSE)
  439.                                 return (FALSE);
  440.                         ++size;
  441.                 }
  442.         }
  443.         curwp->w_dotp = dotp;
  444.         curwp->w_doto = doto;
  445.         return (ldelete(size, TRUE));
  446. }
  447.  
  448. /*
  449.  * Kill backwards by "n" words. Move backwards by the desired number of words,
  450.  * counting the characters. When dot is finally moved to its resting place,
  451.  * fire off the kill command. Bound to "M-Rubout" and to "M-Backspace".
  452.  */
  453. delbword(f, n)
  454. {
  455.         register int    size;
  456.  
  457.         if (n < 0)
  458.                 return (FALSE);
  459.         if (backchar(FALSE, 1) == FALSE)
  460.                 return (FALSE);
  461.         size = 0;
  462.         while (n--) {
  463.                 while (inword() == FALSE) {
  464.                         if (backchar(FALSE, 1) == FALSE)
  465.                                 return (FALSE);
  466.                         ++size;
  467.                 }
  468.                 while (inword() != FALSE) {
  469.                         if (backchar(FALSE, 1) == FALSE)
  470.                                 return (FALSE);
  471.                         ++size;
  472.                 }
  473.         }
  474.         if (forwchar(FALSE, 1) == FALSE)
  475.                 return (FALSE);
  476.         return (ldelete(size, TRUE));
  477. }
  478.  
  479. /*
  480.  * Return TRUE if the character at dot is a character that is considered to be
  481.  * part of a word. The word character list is hard coded. Should be setable.
  482.  */
  483. inword()
  484. {
  485.         register int    c;
  486.  
  487.         if (curwp->w_doto == llength(curwp->w_dotp))
  488.                 return (FALSE);
  489.         c = lgetc(curwp->w_dotp, curwp->w_doto);
  490.         if (c>='a' && c<='z')
  491.                 return (TRUE);
  492.         if (c>='A' && c<='Z')
  493.                 return (TRUE);
  494.         if (c>='0' && c<='9')
  495.                 return (TRUE);
  496.         if (c=='$' || c=='_')                   /* For identifiers      */
  497.                 return (TRUE);
  498.         return (FALSE);
  499. }
  500.  
  501.